package win

import (
	"os"
	"path/filepath"
	"runtime"
	"syscall"
	"unsafe"

	"gitee.com/haifengat/goctp"
	ctp "gitee.com/haifengat/goctp/ctpdefine"
)

type Trade struct {
	goctp.HFTrade
	h        *syscall.DLL
	api, spi uintptr

    [[ range .On]]// [[ .Comment ]]
    _[[ .FuncName ]] func([[ range $i,$v := .FuncFields ]][[ if gt $i 0 ]], [[ end ]][[ .FieldName|trimStar ]] [[ .FieldType|ctp_type ]][[ end ]])
    [[ end]]
}

func (t *Trade) loadDll() {
	workPath, _ := os.Getwd()
	_, curFile, _, ok := runtime.Caller(1)
	if !ok {
		panic("取当前文件路径失败")
	}
	dllPath := filepath.Dir(curFile)
	_ = os.Chdir(dllPath)
	t.h = syscall.MustLoadDLL("ctp_trade.dll")

	// 还原到之前的工作目录
	os.Chdir(workPath)
	//defer h.Release() // 函数结束后会释放导致后续函数执行失败
}

// NewTrade 实例化
func NewTrade() *Trade {
	t := new(Trade)

	// 主调函数封装 手动添加
	t.HFTrade.GetVersion = func() string {
		ver, _, _ := t.h.MustFindProc("tGetVersion").Call()
		p := (*byte)(unsafe.Pointer(ver))
		data := make([]byte, 0)
		for *p != 0 {
			data = append(data, *p)
			ver += unsafe.Sizeof(byte(0))
			p = (*byte)(unsafe.Pointer(ver))
		}
		return string(data)
	}
	t.HFTrade.ReqConnect = func(addr string) {
		bs, _ := syscall.BytePtrFromString(addr)
		t.h.MustFindProc("tRegisterFront").Call(t.api, uintptr(unsafe.Pointer(bs)))
		t.h.MustFindProc("tSubscribePrivateTopic").Call(t.api, uintptr(t.PrivateMode))
		t.h.MustFindProc("tSubscribePublicTopic").Call(t.api, uintptr(ctp.THOST_TERT_RESTART))
		t.h.MustFindProc("tInit").Call(t.api)
		// C.Join(t.api)
	}
	t.HFTrade.ReleaseAPI = func() {
		t.h.MustFindProc("tRelease").Call(t.api)
	}
	t.HFTrade.ReqAuthenticate = func(f *ctp.CThostFtdcReqAuthenticateField, i int) {
		t.h.MustFindProc("tReqAuthenticate").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqUserLogin = func(f *ctp.CThostFtdcReqUserLoginField, i int) {
		t.h.MustFindProc("tReqUserLogin").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqSettlementInfoConfirm = func(f *ctp.CThostFtdcSettlementInfoConfirmField, i int) {
		t.h.MustFindProc("tReqSettlementInfoConfirm").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqQryInstrument = func(f *ctp.CThostFtdcQryInstrumentField, i int) {
		t.h.MustFindProc("tReqQryInstrument").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqQryInvestor = func(f *ctp.CThostFtdcQryInvestorField, i int) {
		t.h.MustFindProc("tReqQryInvestor").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqQryClassifiedInstrument = func(f *ctp.CThostFtdcQryClassifiedInstrumentField, i int) {
		t.h.MustFindProc("tReqQryClassifiedInstrument").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqQryTradingAccount = func(f *ctp.CThostFtdcQryTradingAccountField, i int) {
		t.h.MustFindProc("tReqQryTradingAccount").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqQryInvestorPosition = func(f *ctp.CThostFtdcQryInvestorPositionField, i int) {
		t.h.MustFindProc("tReqQryInvestorPosition").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqOrder = func(f *ctp.CThostFtdcInputOrderField, i int) {
		t.h.MustFindProc("tReqOrderInsert").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqAction = func(f *ctp.CThostFtdcInputOrderActionField, i int) {
		t.h.MustFindProc("tReqOrderAction").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqFromBankToFutureByFuture = func(f *ctp.CThostFtdcReqTransferField, i int) {
		t.h.MustFindProc("tReqFromBankToFutureByFuture").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqFromFutureToBankByFuture = func(f *ctp.CThostFtdcReqTransferField, i int) {
		t.h.MustFindProc("tReqFromFutureToBankByFuture").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqQryOrder = func(f *ctp.CThostFtdcQryOrderField, i int) {
		t.h.MustFindProc("tReqQryOrder").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	t.HFTrade.ReqQryTrade = func(f *ctp.CThostFtdcQryTradeField, i int) {
		t.h.MustFindProc("tReqQryTrade").Call(t.api, uintptr(unsafe.Pointer(f)), uintptr(i))
	}
	
	// HFTrade 响应 手动添加即可增加新功能
	t._RtnFromFutureToBankByFuture = func(pRspTransfer *ctp.CThostFtdcRspTransferField) {
		t.HFTrade.RtnFromFutureToBankByFuture(pRspTransfer)
	}
	t._RtnFromBankToFutureByFuture = func(pRspTransfer *ctp.CThostFtdcRspTransferField) {
		t.HFTrade.RtnFromBankToFutureByFuture(pRspTransfer)
	}
	t._ErrRtnOrderAction = func(pOrderAction *ctp.CThostFtdcOrderActionField, pRspInfo *ctp.CThostFtdcRspInfoField) {
		t.HFTrade.ErrRtnOrderAction(pOrderAction, pRspInfo)
	}
	t._ErrRtnOrderInsert = func(pInputOrder *ctp.CThostFtdcInputOrderField, pRspInfo *ctp.CThostFtdcRspInfoField) {
		t.HFTrade.ErrRtnOrderInsert(pInputOrder, pRspInfo)
	}
	t._RtnTrade = func(pTrade *ctp.CThostFtdcTradeField) {
		t.HFTrade.RtnTrade(pTrade)
	}
	t._RtnOrder = func(pOrder *ctp.CThostFtdcOrderField) {
		t.HFTrade.RtnOrder(pOrder)
	}
	t._RtnInstrumentStatus = func(pInstrumentStatus *ctp.CThostFtdcInstrumentStatusField) {
		t.HFTrade.RtnInstrumentStatus(pInstrumentStatus)
	}
	t._RspQryInvestorPosition = func(pInvestorPosition *ctp.CThostFtdcInvestorPositionField, pRspInfo *ctp.CThostFtdcRspInfoField, nRequestID int, bIsLast bool) {
		if pInvestorPosition == nil{ // 处理空指针
			pInvestorPosition = &ctp.CThostFtdcInvestorPositionField{}
		}
		t.HFTrade.RspQryInvestorPosition(pInvestorPosition, bIsLast)
	}
	t._RspQryTradingAccount = func(pTradingAccount *ctp.CThostFtdcTradingAccountField, pRspInfo *ctp.CThostFtdcRspInfoField, nRequestID int, bIsLast bool) {
		t.HFTrade.RspQryTradingAccount(pTradingAccount, bIsLast)
	}
	t._RspQryTrade = func(pTrade *ctp.CThostFtdcTradeField, pRspInfo *ctp.CThostFtdcRspInfoField, nRequestID int, bIsLast bool) {
		if pTrade == nil{ // 处理空指针
			pTrade = &ctp.CThostFtdcTradeField{}
		}
		t.HFTrade.RspQryTrade(pTrade, bIsLast)
	}
	t._RspQryOrder = func(pOrder *ctp.CThostFtdcOrderField, pRspInfo *ctp.CThostFtdcRspInfoField, nRequestID int, bIsLast bool) {
		if pOrder == nil{ // 处理空指针
			pOrder = &ctp.CThostFtdcOrderField{}
		}
		t.HFTrade.RspQryOrder(pOrder, bIsLast)
	}
	t._RspQryInvestor = func(pInvestor *ctp.CThostFtdcInvestorField, pRspInfo *ctp.CThostFtdcRspInfoField, nRequestID int, bIsLast bool) {
		t.HFTrade.RspQryInvestor(pInvestor, bIsLast)
	}
	t._RspQryInstrument = func(pInstrument *ctp.CThostFtdcInstrumentField, pRspInfo *ctp.CThostFtdcRspInfoField, nRequestID int, bIsLast bool) {
		t.HFTrade.RspQryInstrument(pInstrument, bIsLast)
	}
	t._RspQryClassifiedInstrument = func(pInstrument *ctp.CThostFtdcInstrumentField, pRspInfo *ctp.CThostFtdcRspInfoField, nRequestID int, bIsLast bool) {
		t.HFTrade.RspQryInstrument(pInstrument, bIsLast)
	}
	t._RspSettlementInfoConfirm = func(pSettlementInfoConfirm *ctp.CThostFtdcSettlementInfoConfirmField, pRspInfo *ctp.CThostFtdcRspInfoField, nRequestID int, bIsLast bool) {
		t.HFTrade.RspSettlementInfoConfirm()
	}
	t._RspUserLogin = func(pRspUserLogin *ctp.CThostFtdcRspUserLoginField, pRspInfo *ctp.CThostFtdcRspInfoField, nRequestID int, bIsLast bool) {
		t.HFTrade.RspUserLogin(pRspUserLogin, pRspInfo)
	}
	t._RspAuthenticate = func(pRspAuthenticateField *ctp.CThostFtdcRspAuthenticateField, pRspInfo *ctp.CThostFtdcRspInfoField, nRequestID int, bIsLast bool) {
		t.HFTrade.RspAuthenticate(pRspInfo)
	}
	t._FrontConnected = func() {
		t.HFTrade.FrontConnected()
	}
	t._FrontDisconnected = func(nReason int) {
		t.HFTrade.FrontDisConnected(nReason)
	}

	t.loadDll()
	t.HFTrade.Init() // 能够在 hftrade 中调用函数

	t.api, _, _ = t.h.MustFindProc("tCreateApi").Call()
	t.spi, _, _ = t.h.MustFindProc("tCreateSpi").Call()
	t.h.MustFindProc("tRegisterSpi").Call(t.api, uintptr(t.spi))

    [[ range .On ]]t.h.MustFindProc("tSetOn[[ .FuncName ]]").Call(t.spi, syscall.NewCallback(t.On[[ .FuncName ]]))
    [[ end ]]
	return t
}
[[ range .On ]]
//export t[[ .FuncName ]]
func (t *Trade) On[[ .FuncName ]]([[ range $i, $v := .FuncFields ]][[ if gt $i 0]], [[ end ]][[ .FieldName|trimStar ]] [[ .FieldType|ctp_type]][[ end ]]) uintptr {
    if t._[[ .FuncName ]] != nil{
        t._[[ .FuncName ]]([[ range $i,$v := .FuncFields ]][[ if gt $i 0 ]], [[ end ]][[ .FieldName|trimStar ]][[ end ]])
    }
	return 0
}
[[ end ]]
